package com.example.until;

import com.example.entity.enums.BaseInfoEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.time.Instant;
import java.util.*;

// @Component将这个类标记为 Spring 组件，允许 Spring 管理该类的生命周期，便于依赖注入。
@Component
public class JwtUtil {
    /**
     * 过期时间(单位:秒),4小时为14400s
     */
    public static final int ACCESS_EXPIRE = Integer.parseInt(BaseInfoEnum.fiedIdOf("access_expire").getFiedIdInfo());//14400;
    /**
     * 加密算法
     */
    private final static SecureDigestAlgorithm<SecretKey, SecretKey> ALGORITHM = Jwts.SIG.HS256;
    /**
     * 私钥 / 生成签名的时候使用的秘钥secret，一般可以从本地配置文件中读取，切记这个秘钥不能外露，只在服务端使用，在任何场景都不应该流露出去。
     * 一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
     * 应该大于等于 256位(长度32及以上的字符串)，并且是随机的字符串
     */
    private final static String SECRET = BaseInfoEnum.fiedIdOf("secret").getFiedIdInfo();//"Cpj2cc09BRTstcISP5HtEAMxwuFEh-nJiL1mppdsz8k@lzgs";
    /**
     * 秘钥实例,相比secretkeyspec方法base64编码指定验证方式，该种方式更加简便安全。
     */
    public static final SecretKey KEY = Keys.hmacShaKeyFor(SECRET.getBytes());
    /**
     * jwt签发者
     */
    private final static String JWT_ISS = BaseInfoEnum.fiedIdOf("jwt_iss").getFiedIdInfo();
    /**
     * jwt主题
     */
    private final static String SUBJECT = "Peripherals";

    /**
     * jwt构建器，生成token
     * 这些是一组预定义的声明，它们 不是强制性的，而是推荐的 ，以 提供一组有用的、可互操作的声明 。
     * iss: jwt签发者
     * sub: jwt所面向的用户
     * aud: 接收jwt的一方
     * exp: jwt的过期时间，这个过期时间必须要大于签发时间
     * nbf: 定义在什么时间之前，该jwt都是不可用的.
     * iat: jwt的签发时间
     * jti: jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击
     */
    public static String genAccessToken(String username ,String roleId,String company) {
        // 令牌id
        String uuid = UUID.randomUUID().toString();
        Date exprireDate = Date.from(Instant.now().plusSeconds(ACCESS_EXPIRE));
        //System.out.println("key:"+KEY);
        return Jwts.builder()
                // 设置头部信息header
                .header()
                .add("typ", "JWT")
                .add("alg", "HS256")
                .and()
                // 设置自定义负载信息payload
                .claim("username", username )//
                .claim("roleId",roleId )
                .claim("company",company )
                // 令牌ID
                .id(uuid)
                // 过期日期
                .expiration(exprireDate)
                // 签发时间
                .issuedAt(new Date())
                // 主题
                .subject(SUBJECT)
                // 签发者
                .issuer(JWT_ISS)
                // 签名
                .signWith(KEY, ALGORITHM)
                .compact();
    }
    /**
     * 解析token
     * @param token token
     * @return Jws<Claims>
     */
    public static Jws<Claims> parseClaim(String token) {
        return Jwts.parser()
                .verifyWith(KEY)
                .build()
                .parseSignedClaims(token);
    }

    /**
     * 获取头部信息
     * @param token
     * @return
     */
    public static JwsHeader parseHeader(String token) {
        return parseClaim(token).getHeader();
    }

    /**
     * 获取载荷信息
     * @param token
     * @return
     */
    public static Claims parsePayload(String token) {
        return parseClaim(token).getPayload();
    }

    /**
     * token验证，token是否过期正确
     * @param token
     * @return
     */
    public static boolean validateJwtToken(String token) {
        try {
            // 解析 Token，验证签名。验证载荷
            Claims claims = parseClaim(token).getPayload();
            //System.out.println("content:---"+claims.get("username"));
            // 验证声明（例如过期时间）
            if (claims.getExpiration().before(new Date())) {
                System.out.println("Token has expired.");
                return false;
            }
            // 在这里可以进行其他自定义验证
            // 例如检查用户角色、权限等

            // Token 验证通过
            return true;
        } catch (Exception e) {
            // 验证失败
            System.out.println("Token validation failed: " + e.getMessage());
            return false;
        }
    }

    /**
     * 直接获取到载荷的具体内容
     * @param token
     * @return
     */
    public static Map<String, Object> token2userInfo(String token){
        Map<String, Object> tokenMap = new HashMap<String, Object>();
        Claims claims = parseClaim(token).getPayload();
        tokenMap.put("company", claims.get("company"));
        tokenMap.put("loginName", claims.get("username"));
        tokenMap.put("roleId", claims.get("roleId"));
        return tokenMap;
    }
    //测试
    public static void main(String[] args){
        String token = genAccessToken("123","admin","123");
        System.out.println("token:"+token);
        boolean isValid = validateJwtToken(token);
        System.out.println(isValid);
        System.out.println(parseHeader(token));
        System.out.println(parsePayload(token));
    }

}
